package com.ssb.util.sign;

import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;

/**
 * @author: Don
 * @date: 2018/9/6 17:32
 * @description:
 */
public class RSAHelper {
    private static final String EncodingKey = "GBK";
    /**
     * 私钥
     */
    private PrivateKey _PriKey;
    /**
     * 公钥
     */
    private PublicKey _PubKey;
    /**
     * 算法名称
     */
    private String _SigAlgName;
    public RSAHelper()
    {

    }
    /**
     * 使用 pfx 证书设置私钥
     * @param keyStorePath
     * @param alias
     * @param password
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     * @throws UnrecoverableKeyException
     */
    public void setPrivateKeyByCert(String keyStorePath, String alias, String password)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException
    {
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) CertAndKeyHelper.getCertificate(keyStorePath, alias, password);
        // 获取私钥
        KeyStore keyStore = CertAndKeyHelper.getKeyStore(keyStorePath, password);
        // 取得私钥
        this._PriKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
        // 构建签名
        this._SigAlgName = x509Certificate.getSigAlgName();//"SHA1withRSA";
    }
    /**
     * 使用 xml 文件设置私钥
     * @param xmlFilePath
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public void setPrivateKeyByXml(String xmlFilePath)
            throws IOException, NoSuchAlgorithmException, InvalidKeySpecException
    {
        byte[] privateKeyBytes = IOHelper.fileToBytes(xmlFilePath);
        String privateKeyXmlString = new String(privateKeyBytes, EncodingKey);
        this._PriKey = CertAndKeyHelper.decodePrivateKeyFromXml(privateKeyXmlString);
        // 构建签名
        this._SigAlgName = "SHA1withRSA";
    }
    /**
     * 使用 .cer 的证书设置公钥
     * @param certificatePath
     * @throws CertificateException
     * @throws IOException
     */
    public void setPublicKeyByCert(String certificatePath)
            throws CertificateException, IOException
    {
        // 获得证书
        X509Certificate x509Certificate = (X509Certificate) CertAndKeyHelper.getCertificate(certificatePath);
        // 获得公钥
        this._PubKey = x509Certificate.getPublicKey();
        // 构建签名
        this._SigAlgName = x509Certificate.getSigAlgName();//"SHA1withRSA";
    }
    /**
     * 使用 xml 文件设置公钥
     * @param xmlFilePath
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     * @throws IOException
     */
    public void setPublicKeyByXml(String xmlFilePath) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException
    {
        byte[] publicKeyBytes = IOHelper.fileToBytes(xmlFilePath);
        String publicKeyXmlString = new String(publicKeyBytes, this.EncodingKey);
        this._PubKey = CertAndKeyHelper.decodePublicKeyFromXml(publicKeyXmlString);
        this._SigAlgName = "SHA1withRSA";
    }
    /**
     * 对 Base64 编码的源数据进行签名，返回签名后的值的 Base64 值
     * @param dataBase64
     * @return
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    public String sign(String dataBase64) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
    {
        byte[] signatureData = sign(Base64Helper.decode(dataBase64));
        return Base64Helper.encode(signatureData);
    }
    /**
     * 对 源数据进行签名，返回签名后的值
     * @param data
     * @return
     * @throws SignatureException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public byte[] sign(byte[] data) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
    {
        // 构建签名
        String sigAlgName = this._SigAlgName;
        Signature signature = Signature.getInstance(sigAlgName);
        signature.initSign(this._PriKey);
        signature.update(data);
        return signature.sign();
    }
    /**
     * 对 Base64 编码的源数据,和签名后的值的 Base64 值进行验签
     * @param dataBase64
     * @param signatureDataBase64
     * @return
     * @throws NoSuchAlgorithmException
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    public boolean verifySign(String dataBase64, String signatureDataBase64) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
    {
        byte[] data = Base64Helper.decode(dataBase64);
        byte[] signatureData = Base64Helper.decode(signatureDataBase64);
        return verifySign(data, signatureData);
    }
    /**
     * 对 源数据和签名后的值进行验签
     * @param data
     * @param signatureData
     * @return
     * @throws SignatureException
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     */
    public boolean verifySign(byte[] data, byte[] signatureData) throws SignatureException, InvalidKeyException, NoSuchAlgorithmException
    {
        try
        {
            Signature signature = Signature.getInstance(this._SigAlgName);
            signature.initVerify(this._PubKey);
            signature.update(data);
            return signature.verify(signatureData);
        }
        catch (Exception ex)
        {
            System.out.println("发生异常：" + ex.getMessage());
            return false;
        }

    }
}
